package com.hsurosy.domain.strategy.service.raffle;

import com.hsurosy.domain.strategy.model.entity.StrategyAwardEntity;
import com.hsurosy.domain.strategy.model.valobj.RuleTreeVO;
import com.hsurosy.domain.strategy.model.valobj.StrategyAwardRuleModelVO;
import com.hsurosy.domain.strategy.model.valobj.StrategyAwardStockKeyVO;
import com.hsurosy.domain.strategy.repository.IStrategyRepository;
import com.hsurosy.domain.strategy.service.AbstractRaffleStrategy;
import com.hsurosy.domain.strategy.service.IRaffleAward;
import com.hsurosy.domain.strategy.service.IRaffleStock;
import com.hsurosy.domain.strategy.service.armory.IStrategyDispatch;
import com.hsurosy.domain.strategy.service.rule.chain.ILogicChain;
import com.hsurosy.domain.strategy.service.rule.chain.factory.DefaultChainFactory;
import com.hsurosy.domain.strategy.service.rule.tree.factory.DefaultTreeFactory;
import com.hsurosy.domain.strategy.service.rule.tree.factory.engine.IDecisionTreeEngine;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.List;

/**
 * @Author Hsu琛君珩
 * @Date 2024-10-17 19:05
 * @Description 默认的抽奖策略实现
 * @Version: v1.0.0
 */
@Slf4j
@Service
public class DefaultRaffleStrategy extends AbstractRaffleStrategy implements IRaffleAward, IRaffleStock {

    // 构造函数，注入必要的依赖
    public DefaultRaffleStrategy(IStrategyRepository repository, IStrategyDispatch strategyDispatch, DefaultChainFactory defaultChainFactory, DefaultTreeFactory defaultTreeFactory) {
        super(repository, strategyDispatch, defaultChainFactory, defaultTreeFactory);
    }

    /**
     * 实现责任链处理逻辑。
     * 责任链处理抽奖的前置规则，例如黑名单、权重等规则。
     *
     * @param userId 用户ID
     * @param strategyId 策略ID
     * @return 抽奖责任链处理后的奖品信息
     */
    @Override
    public DefaultChainFactory.StrategyAwardVO raffleLogicChain(String userId, Long strategyId) {
        // 打开责任链，根据策略ID获取适用的责任链
        ILogicChain logicChain = defaultChainFactory.openLogicChain(strategyId);
        // 执行责任链逻辑，返回处理结果
        return logicChain.logic(userId, strategyId);
    }

    /**
     * 实现决策树的规则过滤逻辑。
     * 在责任链处理完后，调用该方法继续执行规则树过滤，如奖品次数限制、库存检查和兜底奖励等。
     *
     * @param userId 用户ID
     * @param strategyId 策略ID
     * @param awardId 奖品ID，责任链处理后的奖品ID
     * @return 经过规则过滤后的最终奖品信息
     */
    @Override
    public DefaultTreeFactory.StrategyAwardVO raffleLogicTree(String userId, Long strategyId, Integer awardId) {
        // 从仓储中获取奖品的规则模型
        StrategyAwardRuleModelVO strategyAwardRuleModelVO = repository.queryStrategyAwardRuleModelVO(strategyId, awardId);
        // 如果没有规则模型，直接返回当前奖品ID
        if (null == strategyAwardRuleModelVO) {
            return DefaultTreeFactory.StrategyAwardVO.builder().awardId(awardId).build();
        }

        // 根据规则模型获取对应的规则树
        RuleTreeVO ruleTreeVO = repository.queryRuleTreeVOByTreeId(strategyAwardRuleModelVO.getRuleModels());
        if (null == ruleTreeVO) {
            // 如果没有找到规则树，抛出异常，表明配置中存在问题
            throw new RuntimeException("存在抽奖策略配置的规则模型 Key，未在库表 rule_tree、rule_tree_node、rule_tree_node_line 配置对应的规则树信息 " + strategyAwardRuleModelVO.getRuleModels());
        }

        // 打开规则树引擎，执行规则树逻辑过滤
        IDecisionTreeEngine treeEngine = defaultTreeFactory.openLogicTree(ruleTreeVO);
        // 返回规则过滤后的结果，通常是过滤后的奖品ID
        return treeEngine.process(userId, strategyId, awardId);
    }

    /**
     * 从队列中获取库存分配的奖品数据
     *
     * @return 抽奖奖品的库存分配数据
     * @throws InterruptedException 如果线程被中断时抛出异常
     */
    @Override
    public StrategyAwardStockKeyVO takeQueueValue() throws InterruptedException {
        // 调用仓储层，从队列中获取分配的奖品库存信息
        return repository.takeQueueValue();
    }

    /**
     * 更新指定策略的奖品库存信息
     *
     * @param strategyId 抽奖策略ID
     * @param awardId 奖品ID
     */
    @Override
    public void updateStrategyAwardStock(Long strategyId, Integer awardId) {
        // 调用仓储层，更新指定策略和奖品ID对应的库存信息
        repository.updateStrategyAwardStock(strategyId, awardId);
    }

    /**
     * 查询指定策略的奖品列表
     *
     * @param strategyId 抽奖策略ID
     * @return 返回该策略对应的奖品列表
     */
    @Override
    public List<StrategyAwardEntity> queryRaffleStrategyAwardList(Long strategyId) {
        // 从仓储层查询并返回奖品列表
        return repository.queryStrategyAwardList(strategyId);
    }

}
